/*
 * Copyright (C) 2020  Prasoon Joshi
 *
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

package models

import java.util.UUID

import generated._
import play.api.data._
import play.api.data.Forms._


/*
Some basic things to understand about the EAD3 elements and attributes:
>> Formatting and Data are entangled together
 */
case class ItemData(id: UUID, title: String)

object FormItem {
  val itemForm = Form(
    mapping(
      "id" -> uuid,
      "title"  -> nonEmptyText
    )(ItemData.apply)(ItemData.unapply)
  )
}

trait Identifiable {
  def id: String
}
//TODO: Have a trait that enforces processing related details for Repo, Fond, Series, File, Item
case class ArchiveHoldings(id: String,
                           name: String = "repository",
                           fonds: Option[List[Fond]]) extends Identifiable
//TODO: Fond as union of RecordGroup and ManuscriptGroup
case class Fond(id: String,
                name: String,
                processingDate: Long,
                subFond: Option[List[Fond]],
                series: Option[List[Series]],
                donor: Donor) extends Identifiable
case class Series(id: String,
                  name: String,
                  processingDate: Long,
                  subSeries: Option[List[Series]]) extends Identifiable
case class File(id: String,
                name: String,
                processingDate: Long,
                items: Option[List[Item_]]) extends Identifiable

object Condition extends Enumeration {
  type Condition = Value
  val GOOD, FRAGILE = Value
}

//TODO: Each section of the encoding standard like EAD would become one type!

trait Item_ extends Identifiable {
  def name: String
  def processingDate: Long
  def creator: Option[List[Person]]
  def condition: Condition.Value
}
case class MovingImage(id: String,
                       name: String,
                       processingDate: Long,
                       creator: Option[List[MovieMaker]],
                       condition: Condition.Value) extends Item_
case class Book(id: String,
                name: String,
                processingDate: Long,
                creator: Option[List[Author]],
                condition: Condition.Value) extends Item_
case class Flyer(id: String,
                 name: String,
                 processingDate: Long,
                 creator: Option[List[Artist]],
                 condition: Condition.Value) extends Item_


//TODO: Code review to be done by a legal expert
/* Begin: Legal Items */
trait Court {
}
//TODO: Make `city` type-safe.
case class HighCourt(name: String,
                     city: String) extends Court
case class SupremeCourt(name: String) extends Court
trait LegalPapers extends Item_ {
  def origin: Court
}

case class SpecialLeavePetition(id: String,
                                name: String,
                                origin: Court,
                                processingDate: Long,
                                creator: Option[List[Petitioner]],
                                condition: Condition.Value) extends LegalPapers
case class WritPetition(id: String,
                        name: String,
                        origin: Court,
                        processingDate: Long,
                        creator: Option[List[Petitioner]],
                        condition: Condition.Value) extends LegalPapers
/* End: Legal Items */

//TODO: What convention should be followed for names of Persons? Do we need 'firstName + lastName'?
trait Person extends Identifiable {
  def name: String
}

case class Donor(id: String,
                 name: String) extends Person
case class MovieMaker(id: String,
                      name: String) extends Person
case class Author(id: String,
                  name: String) extends Person
case class Artist(id: String,
                  name: String) extends Person


/* Begin: Legal Person types */
trait LegalPerson extends Person {

}
case class Applicant(id: String,
                     name: String) extends LegalPerson
case class Petitioner(id: String,
                      name: String) extends LegalPerson
/* End: Legal Person types */


//Begin: Input models

/*
Encoded Archival Description describes the entire Fond along with
the control, archival description.
 */
case class EadInput(control: ControlInput)
case object EadInput {
  def toEad(ead: EadInput): Ead = ???
  def toXml(ead: EadInput) = scalaxb.toXML(toEad(ead), "ead", defaultScope)
}

/*
Control section:
Encoding information like countryEncoding, langEncoding, scriptEncoding,
repositoryEncoding, dateEncoding could be pulled from install time configuration.
TODO: Think of a way to change this later from the UI
 */
case class ControlInput(titleProper: String,
                        publisherId: String,
                        pubLicenseId: String,
                        maintenanceAgencyId: String,
                        languageCode: String,
                        scriptCode: String,
                        agendId: String,
                        countryEncoding: String = "Isoasdf")

object AgentTypeEnum extends Enumeration {
  type AgentType = Value
  val Human, Machine, Unknown = Value
}

case class Agent(id: String,
                 name: String,
                 agentType: AgentTypeEnum.AgentType)

//End: Input models